/**
 * 用户自定义字段
 *
 */
const mongoose = require('mongoose');
const UserDefinedFields = require('./mongo/user-defined-fields');
const PhoenixError = require('./phoenix-error');
const projectVersionModel = require('./project-versions');
const Function = require('./mongo/function');
const TestCase = require('./mongo/test-case');

async function createUserDefinedField({
  domain,
  scope,
  name,
} = {}) {
  const exists = await UserDefinedFields.findOne({
    domain,
    scope,
    name,
  });
  if (!domain || !scope || !name) {
    throw new PhoenixError('invalid request', 'need domain, scope and name');
  }
  if (exists) {
    throw new PhoenixError('conflict', `${domain} ${scope} ${name} already exists`);
  }
  const fieldsList = await UserDefinedFields.find({
    domain,
    scope,
    index: { $exists: 1 },
  }, {}, { sort: { index: -1 } }).limit(1);
  let fieldIndex = 0;
  if (fieldsList.length > 0) {
    fieldIndex = fieldsList[0].index + 1;
  }
  return UserDefinedFields.create({
    domain, scope, name, index: fieldIndex,
  });
}

async function deleteUserDefinedField(_udfId) {
  const udfId = mongoose.Types.ObjectId(_udfId);
  const exists = await UserDefinedFields.findById(udfId);
  if (!exists) {
    throw new PhoenixError('not found', `user defined field ${_udfId} not found`);
  }
  // 删除用户定义的自定义字段
  let model;
  switch (exists.scope) {
    case 'function':
      model = Function;
      break;
    case 'testcase':
      model = TestCase;
      break;
    default:
      throw new Error(`wrong scope ${exists.scope}`);
  }
  await model.collection.updateMany({
    userDefinedFields: {
      $elemMatch: {
        key: udfId,
      },
    },
  }, {
    $pull: {
      userDefinedFields: {
        key: udfId,
      },
    },
  });
  await exists.remove();
}

async function listUserDefinedField(domain, scope) {
  const filter = {};
  if (domain) {
    filter.$or = [{ domain }];
    if (domain === projectVersionModel.versionType.unitTest) filter.$or.push({ domain: { $exists: false } });
  }
  if (scope) filter.scope = scope;
  const list = await UserDefinedFields.find(filter, {}, { sort: { index: 1 } });
  return { list };
}

async function modifyUserDefinedField(_udfId, fieldsName) {
  if (fieldsName === '') {
    throw new PhoenixError('invalid request', 'need name');
  }
  const udfId = mongoose.Types.ObjectId(_udfId);
  const exists = await UserDefinedFields.findById(udfId);
  if (!exists) {
    throw new PhoenixError('not found', `user defined field ${_udfId} not found`);
  }
  const { domain, scope } = exists;
  const conflictField = await UserDefinedFields.findOne({
    domain,
    scope,
    name: fieldsName,
  });
  if (conflictField) {
    throw new PhoenixError('conflict', 'name already exists');
  }
  const modifyField = await UserDefinedFields.findByIdAndUpdate(
    udfId,
    {
      name: fieldsName,
    }, {
      new: true,
    }
  );
  // remove index field
  const { index, ...modifyFieldReshape } = modifyField.toObject();
  return modifyFieldReshape;
}

async function transposeUserDefinedField(fieldIdsList) {
  const opsList = [];
  fieldIdsList.forEach((id, idIndex) => {
    const fieldId = mongoose.Types.ObjectId(id);
    const updateMsg = {
      updateOne: {
        filter: { _id: fieldId },
        update: { $set: { index: idIndex } },
      },
    };
    opsList.push(updateMsg);
  });
  await UserDefinedFields.bulkWrite(opsList);
}

module.exports = {
  createUserDefinedField,
  deleteUserDefinedField,
  listUserDefinedField,
  modifyUserDefinedField,
  transposeUserDefinedField,
};
exports = Object.assign(exports, module.exports);
